package com.dly.hope.aop;

import com.dly.hope.annotation.Clear;
import com.dly.hope.annotation.SysLog;
import com.dly.hope.utils.JsonFormatUtil;
import com.dly.hope.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class CacheAop {

    @Resource
    private RedisUtil redisUtil;

    private Map<String, List<String>> cathe = new ConcurrentHashMap<>();

    @Pointcut(value = "@annotation(com.dly.hope.annotation.Clear)")
    public void clearCut(){}

    @Around(value = "clearCut()")
    public Object clearCache(ProceedingJoinPoint point) throws Throwable {

        Object proceed = point.proceed();

        MethodSignature method = (MethodSignature) point.getSignature();
        Clear clear = method.getMethod().getAnnotation(Clear.class);
        //清除那个类
        String className = clear.clazz().getName();
        //那个类下的方法
        String[] methodNames = clear.methodName();
        for (int i = 0; i < methodNames.length; i++) {
            List<String> clearStr= cathe.get(className + ":" + methodNames[i]);
            if(!Objects.isNull(clearStr)){
                clearStr.forEach(s -> redisUtil.removeStr(s));
            }
            cathe.remove(className + ":" + methodNames[i]);
        }

        return proceed;
    }

    @Pointcut(value = "@annotation(com.dly.hope.annotation.SysLog)")
    public void pointCut(){}

    @Around(value = "pointCut()")
    public Object addCache(ProceedingJoinPoint point) throws Throwable {
        StringBuilder redisKey = new StringBuilder("AOP").append("::");

        //全类名
        String className = point.getTarget().toString().split("@")[0];
        redisKey.append(className).append("::");


        //方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        String methodName = signature.getName();
        redisKey.append(methodName);


        //返回值
        Class<?> returnType = signature.getReturnType();

        //参数
        Object[] args = point.getArgs();
        if(args!=null && args.length > 0){
            for (int i = 0; i < args.length; i++) {
                redisKey.append(":").append(args[i]);
            }
        }


        String key = redisKey.toString();

        //对key进行保存方便清除
        List<String> strKeys = cathe.get(className+":"+methodName);
        if(Objects.isNull(strKeys)){
            List<String> keys = new ArrayList<>();
            keys.add(key);
            cathe.put(className+":"+methodName, keys);
        }else{
            strKeys.add(key);
        }

        log.info("redis-key:"+key);
        String result = redisUtil.getStr(key);

        if(result == null ){
            Object res = point.proceed();
            long expire = signature.getMethod().getAnnotation(SysLog.class).expire();
            redisUtil.setStr(key, JsonFormatUtil.writeToJson(res), expire, TimeUnit.SECONDS);
            return res;
        }

        return JsonFormatUtil.readFromJsonString(result, returnType);
    }
}
